﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using Microsoft.ServiceBus;
using nwrole.lib;
using nwrole.toolbox.sync.contract;
using nwrole.toolbox.sync.service;

namespace nwrole.toolbox.sync.ServiceHost
{
    public class SyncSourceServiceHost
    {
        private System.ServiceModel.ServiceHost host;
        private System.ServiceModel.ServiceHost localHost;

        public void Start(ServiceConnectionInfo connInfo, string srcDbConStr, string syncDbConStr, ServiceConnectionInfo syncDestServiceConnInfo, TimeSpan syncLockSpan)
        {
            if(connInfo.Type == ServiceConnectionInfo.ServiceConnectionType.ServiceBus)
                StartServiceBus(connInfo, srcDbConStr, syncDbConStr, syncDestServiceConnInfo, syncLockSpan);
            else
                StartWebService(connInfo, srcDbConStr, syncDbConStr, syncDestServiceConnInfo, syncLockSpan);
        }

        private void StartServiceBus(ServiceConnectionInfo connInfo, string srcDbConStr, string syncDbConStr, ServiceConnectionInfo syncDestServiceConnInfo, TimeSpan syncLockSpan)
        {
            Trace.TraceInformation("SyncSourceServiceHost ServiceBus starting");
            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;

            TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
            sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(connInfo.ServiceBusIssuerName, connInfo.ServiceBusIssuerSecret);
            
            Uri baseAddress = ServiceBusEnvironment.CreateServiceUri("sb", connInfo.ServiceBusServiceNamespace, connInfo.ServiceBusServicePath);

            System.ServiceModel.ServiceHost host = new System.ServiceModel.ServiceHost(typeof(SyncSourceService), baseAddress);
            try
            {
                host.Description.Behaviors.Add(new ParamServiceBehavior<SyncSrcServiceParams>(new SyncSrcServiceParams(srcDbConStr, syncDbConStr, syncDestServiceConnInfo, DataProviderType.Sql, syncLockSpan)));

                IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);

                ContractDescription contractDescription = ContractDescription.GetContract(typeof(ISyncSourceService), typeof(SyncSourceService));
                ServiceEndpoint serviceEndPoint = new ServiceEndpoint(contractDescription);
                serviceEndPoint.Address = new EndpointAddress(baseAddress);
                serviceEndPoint.Binding = new NetTcpRelayBinding();
                serviceEndPoint.Binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.RelayAccessToken);
                host.Description.Endpoints.Add(serviceEndPoint);

                foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
                {
                    endpoint.Behaviors.Add(serviceRegistrySettings);
                    endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
                }

                host.Faulted += new EventHandler(svcHost_Faulted);
                host.Opened += new EventHandler(svcHost_Opened);
                host.Opening += new EventHandler(svcHost_Opening);
                host.Closed += new EventHandler(svcHost_Closed);
                host.UnknownMessageReceived += new EventHandler<UnknownMessageReceivedEventArgs>(svcHost_UnknownMessageReceived);

                host.Open();

                Trace.TraceInformation("SyncSourceServiceHost ServiceBus started address: " + baseAddress);
            }
            catch (CommunicationException ce)
            {
                Trace.TraceError("An exception occurred with place {0}: {1}", "myplace", ce.Message);
                host.Abort();
            }

            /*Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.WriteLine();
            Console.ReadLine();

            host.Close();*/

        }

        private void StartWebService(ServiceConnectionInfo connInfo, string srcDbConStr, string syncDbConStr, ServiceConnectionInfo syncDestServiceConnInfo, TimeSpan syncLockSpan)
        {
            Trace.TraceInformation("SyncSourceServiceHost WebService starting");

            host = new System.ServiceModel.ServiceHost(typeof(SyncSourceService), new Uri("net.tcp://" + connInfo.WebServiceBaseAddress));
            host.Description.Behaviors.Add(new ParamServiceBehavior<SyncSrcServiceParams>(new SyncSrcServiceParams(srcDbConStr, syncDbConStr, syncDestServiceConnInfo, DataProviderType.Sql, syncLockSpan)));

            NetTcpBinding binding1 = new NetTcpBinding(SecurityMode.None);
            binding1.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
            binding1.MaxBufferSize = 200000000;
            binding1.MaxReceivedMessageSize = 200000000;
            binding1.MaxBufferPoolSize = 200000000;
            binding1.ReaderQuotas.MaxDepth = 32;
            binding1.ReaderQuotas.MaxArrayLength = 200000000;
            binding1.ReaderQuotas.MaxStringContentLength = 200000000;

            host.AddServiceEndpoint(typeof(ISyncSourceService), binding1, connInfo.WebServiceAddress);

            NetTcpBinding binding2 = new NetTcpBinding(SecurityMode.None);
            binding2.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
            binding2.MaxBufferSize = 200000000;
            binding2.MaxReceivedMessageSize = 200000000;
            binding2.MaxBufferPoolSize = 200000000;
            binding2.ReaderQuotas.MaxDepth = 32;
            binding2.ReaderQuotas.MaxArrayLength = 200000000;
            binding2.ReaderQuotas.MaxStringContentLength = 200000000;

            host.AddServiceEndpoint(typeof(ISyncSourceService), binding2, "LocalService");


            /*ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();
            metadataBehavior.HttpGetEnabled = true;
            svcHost.Description.Behaviors.Add(metadataBehavior);
            svcHost.AddServiceEndpoint(typeof (IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(),"mex");*/
            host.Faulted += new EventHandler(svcHost_Faulted);
            host.Opened += new EventHandler(svcHost_Opened);
            host.Opening += new EventHandler(svcHost_Opening);
            host.Closed += new EventHandler(svcHost_Closed);
            host.UnknownMessageReceived += new EventHandler<UnknownMessageReceivedEventArgs>(svcHost_UnknownMessageReceived);
            host.Open();

            /*Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.WriteLine();
            Console.ReadLine();*/

            Trace.TraceInformation("SyncSourceServiceHost WebService started");
        }

        /*private void StartLocalService(ServiceConnectionInfo connInfo, string srcDbConStr, ServiceConnectionInfo syncDestServiceConnInfo)
        {
            localHost = new System.ServiceModel.ServiceHost(typeof(SyncSourceService), new Uri("net.tcp://localhost:8192"));
            localHost.Description.Behaviors.Add(new ParamServiceBehavior<SyncSrcServiceParams>(new SyncSrcServiceParams(srcDbConStr, syncDestServiceConnInfo, DataProviderType.Sql)));
            localHost.AddServiceEndpoint(typeof(ISyncSourceService), new NetTcpBinding(SecurityMode.None), "LocalService");

            localHost.Faulted += new EventHandler(svcHost_Faulted);
            localHost.Opened += new EventHandler(svcHost_Opened);
            localHost.Opening += new EventHandler(svcHost_Opening);
            localHost.Closed += new EventHandler(svcHost_Closed);
            localHost.UnknownMessageReceived += new EventHandler<UnknownMessageReceivedEventArgs>(svcHost_UnknownMessageReceived);
            localHost.Open();
        }*/

        public void Close()
        {
            localHost.Close();
            host.Close();
        }

        void svcHost_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
        {
            Trace.TraceInformation("SyncSourceServiceHost Unkown message received");
        }

        void svcHost_Closed(object sender, EventArgs e)
        {
            Trace.TraceInformation("SyncSourceServiceHost Closed");
        }

        void svcHost_Opening(object sender, EventArgs e)
        {
            Trace.TraceInformation("SyncSourceServiceHost Opening");
        }

        void svcHost_Opened(object sender, EventArgs e)
        {
            Trace.TraceInformation("SyncSourceServiceHost Opened");
        }

        void svcHost_Faulted(object sender, EventArgs e)
        {
            Trace.TraceError("SyncSourceServiceHost Faulted");
        }
    }
}
